package com.syh.jn.scm.infrastructure.repository.impl.supplier.sale;

import cn.redscarf.commons.util.other.ExtStringUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.syh.core.ddd.infrastructure.repository.AggregateRepoMybatisImplTmpl;
import com.syh.jn.scm.domain.supplier.repository.sale.SaleOrderReadRepository;
import com.syh.jn.scm.dto.supplier.sale.SaleOrderItemVo;
import com.syh.jn.scm.dto.supplier.sale.SaleOrderVo;
import com.syh.jn.scm.dto.supplier.sale.SaleStatisticalAmountVo;
import com.syh.jn.scm.infrastructure.repository.model.sale.SaleOrderItemModel;
import com.syh.jn.scm.infrastructure.repository.model.sale.SaleOrderModel;
import com.syh.jn.scm.infrastructure.repository.utils.MybatisTemplate;
import com.syh.jn.scm.infrastructure.repository.utils.SQLAliasGenerateUtil;
import com.syh.jn.scm.infrastructure.wrapper.BaseResolve;
import com.syh.jn.scm.infrastructure.wrapper.ResolveToSQL;
import lombok.extern.java.Log;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 销售订单查询
 */
@Log
@Repository("saleOrderReadRepositoryMbImpl")
public class SaleOrderReadRepositoryMbImpl implements SaleOrderReadRepository {
  private AggregateRepoMybatisImplTmpl<SaleOrderVo, SaleOrderModel, Long> orderImpl =
          new AggregateRepoMybatisImplTmpl.Builder().listTypeClass(SaleOrderVo.class).modelClass(SaleOrderModel.class).build();
  private AggregateRepoMybatisImplTmpl<SaleOrderItemVo, SaleOrderItemModel, Long> itemImpl =
          new AggregateRepoMybatisImplTmpl.Builder().listTypeClass(SaleOrderItemVo.class).modelClass(SaleOrderItemModel.class).build();

  @Override
  public boolean saleItemExistsById(String column, Long id) {
    Wrapper wrapper = Wrapper.build().append(Restrictions.eq(column,id));
    return this.itemImpl.getCount(wrapper) > 0;
  }

  @Override
  public SaleOrderItemVo getByGoodsId(Long goodsId, Long id) {
    Wrapper wrapper = Wrapper.build().append(Restrictions.eq("goodsId",goodsId)).append(Restrictions.eq("id",id));
    return this.itemImpl.getOne(wrapper);
  }

  @Override
  public SaleStatisticalAmountVo statisticalAmount(Wrapper wrapper) {
    SQL sql = new SQL() {{
      SELECT(
              "SUM(saleOrder.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(saleOrder.TOTAL_OUT_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_SALE_ORDER saleOrder");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    BaseResolve resolveToSQL = new ResolveToSQL(wrapper,this.orderImpl.getWrapperParseMethods());
    sqlString.append(" WHERE 1 = 1").append(resolveToSQL.resolve());
    Map<String, Object> list = MybatisTemplate.selectOne(sqlString.toString());
    SaleStatisticalAmountVo saleStatisticalAmountVo = JSONObject.parseObject(JSONObject.toJSONString(list), SaleStatisticalAmountVo.class);
    return saleStatisticalAmountVo;
  }

  @Override
  public SaleStatisticalAmountVo statisticalAmountByOrder(Wrapper we) {

    StringBuffer sqlString = new StringBuffer("SELECT ");
    sqlString.append("SUM(saleOrder.totalAmount) AS statisticalTotalAmount, ");
    sqlString.append("SUM(saleOrder.totalOutAmount) AS statisticalTotalOutAmount ");
    sqlString.append("FROM ( ");

    StringBuffer subString = new StringBuffer(this.orderImpl.getQuerySql().toString());
    BaseResolve resolveToSQL;
    if (this.orderImpl.getWrapperParseMethods() == null) {
      resolveToSQL = new ResolveToSQL(we);
    } else {
      resolveToSQL = new ResolveToSQL(we, this.orderImpl.getWrapperParseMethods());
    }
    subString.append(" WHERE 1=1 ");
    subString.append(resolveToSQL.resolve());
    sqlString.append(subString).append(" ) saleOrder");

    Map<String, Object> map = MybatisTemplate.selectOne(sqlString.toString());
    SaleStatisticalAmountVo vo = JSONObject.parseObject(JSONObject.toJSONString(map),SaleStatisticalAmountVo.class);
    return vo;
  }

  @Override
  public List<SaleStatisticalAmountVo> statisticalAmountByGoods(Wrapper wrapper) {
    BaseResolve resolveToSQL = new ResolveToSQL(wrapper,this.orderImpl.getWrapperParseMethods());
    SQL sql = new SQL() {{
      SELECT(
              "goods.CODE AS goodsCode",
              "goods.NAME AS goodsName",
              "SUM(saleItem.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(saleItem.OUT_TOTAL_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_SALE_ORDER saleOrder");
      INNER_JOIN("T_SALE_ORDER_ITEM saleItem ON saleOrder.ID = saleItem.SALE_ORDER_ID");
      INNER_JOIN("T_BASE_GOODS goods ON saleItem.GOODS_ID = goods.ID");
      WHERE(resolveToSQL.resolveQueryCondition());
      GROUP_BY("goods.CODE","goods.NAME");
      ORDER_BY("SUM(saleItem.OUT_TOTAL_AMOUNT) DESC");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    sqlString.append(" LIMIT 0,10");
    List<Map<String, Object>> list = MybatisTemplate.selectList(sqlString.toString());
    List<SaleStatisticalAmountVo> saleStatisticalAmountVos = JSONArray.parseArray(JSONObject.toJSONString(list), SaleStatisticalAmountVo.class);
    return saleStatisticalAmountVos;
  }

  @Override
  public List<SaleStatisticalAmountVo> statisticalAmountByCustomer(Wrapper we) {
    BaseResolve resolveToSQL = new ResolveToSQL(we,this.orderImpl.getWrapperParseMethods());
    SQL sql = new SQL() {{
      SELECT(
              "downstream.CODE AS downstreamCode",
              "downstream.NAME AS downstreamName",
              "SUM(saleOrder.TOTAL_AMOUNT) AS statisticalTotalAmount",
              "SUM(saleOrder.TOTAL_OUT_AMOUNT) AS statisticalTotalOutAmount"
      );
      FROM("T_SALE_ORDER saleOrder");
      INNER_JOIN("T_BASE_DOWNSTREAM downstream ON saleOrder.DOWN_STREAM_COMPANY_ID = downstream.ID");
      WHERE(resolveToSQL.resolveQueryCondition());
      GROUP_BY("downstream.CODE","downstream.NAME");
      ORDER_BY("SUM(saleOrder.TOTAL_OUT_AMOUNT) DESC");
    }};
    StringBuffer sqlString = new StringBuffer(sql.toString());
    sqlString.append(" LIMIT 0,10");
    List<Map<String, Object>> list = MybatisTemplate.selectList(sqlString.toString());
    List<SaleStatisticalAmountVo> saleStatisticalAmountVos = JSONArray.parseArray(JSONObject.toJSONString(list), SaleStatisticalAmountVo.class);
    return saleStatisticalAmountVos;
  }

  @Override
  public SaleOrderItemVo getItemByItemId(Long id) {
    return this.itemImpl.getById(id);
  }

  @Override
  public List<SaleOrderItemVo> getItemsBySaleOrderIds(Long[] saleOrderIds) {
    Wrapper wrapper = Wrapper.build().append(Restrictions.in("saleOrderId",saleOrderIds));
    return this.itemImpl.getList(wrapper);
  }

  @Override
  public List<SaleOrderItemVo> getItemsBySaleOrderId(Long saleOrderId) {
    Wrapper wrapper = Wrapper.build().append(Restrictions.eq("saleOrderId",saleOrderId));
    return this.itemImpl.getList(wrapper);
  }

  @Override
  public SaleOrderVo getById(Long id) {
    SaleOrderVo saleOrderVo = this.orderImpl.getById(id);
    if (saleOrderVo == null ) {
      return saleOrderVo;
    }
    saleOrderVo.setItems(this.getItemsBySaleOrderId(saleOrderVo.getId()));
    return saleOrderVo;
  }

  @Override
  public SaleOrderVo getOne(Wrapper wrapper) {
    SaleOrderVo saleOrderVo = this.orderImpl.getOne(wrapper);
    saleOrderVo.setItems(this.getItemsBySaleOrderId(saleOrderVo.getId()));
    return saleOrderVo;
  }

//  private List<SaleOrderItemVo> getItemsByOrderId(Long id) {
//    Wrapper wrapper = Wrapper.build().append(Restrictions.eq("saleOrderId",id));
//    return this.itemImpl.getList(wrapper);
//  }

  @Override
  public boolean contains(Long id) {
    return this.orderImpl.contains(id);
  }

  @Override
  public List <SaleOrderVo> getList(Wrapper wrapper) {
    return this.orderImpl.getList(wrapper);
  }

  @Override
  public List <SaleOrderVo> findListPage(Wrapper wrapper, Integer startRow, Integer count) {
    return this.orderImpl.findListPage(wrapper,startRow,count);
  }

  @Override
  public int getCount(Wrapper wrapper) {
    StringBuffer sqlSb = new StringBuffer();
    String viewSql = this.orderImpl.getQuerySql().toString();
    String viewSqlAry[] = viewSql.split("\\s*FROM\\s*");
    sqlSb.append("SELECT COUNT(DISTINCT saleOrder.ID) AS COUNT FROM ");
    for (int i = 1; i <= viewSqlAry.length - 1; i++) {
      if (i > 1) {
        sqlSb.append(" FROM ").append(viewSqlAry[i]);
      } else {
        sqlSb.append(viewSqlAry[i]);
      }
    }
    BaseResolve resolveToSQL = new ResolveToSQL(wrapper, this.orderImpl.getWrapperParseMethods());
    sqlSb.append(" WHERE 1=1 ");
    sqlSb.append(resolveToSQL.resolve());

    Map resultM = MybatisTemplate.selectOne(sqlSb.toString());
    return Integer.parseInt(resultM.get("COUNT").toString());
  }

  public SaleOrderReadRepositoryMbImpl() {
    SQL saleOrderSql = new SQL() {{
      SELECT("DISTINCT NULL",
              SQLAliasGenerateUtil.aliasGenerate(SaleOrderModel.class, "saleOrder", null),
              "businessEntity.NAME AS businessEntityName"
      );
      FROM("T_SALE_ORDER saleOrder");
      LEFT_OUTER_JOIN("T_BASE_DOWNSTREAM businessEntity ON saleOrder.DOWN_STREAM_COMPANY_ID = businessEntity.ID");
      LEFT_OUTER_JOIN("T_SALE_ORDER_ITEM item ON item.SALE_ORDER_ID = saleOrder.ID");
    }};
    this.orderImpl.setQuerySql(saleOrderSql);
    //初始化查询条件解析 saleOrderMap
    Map<String, String> saleOrderMap = new HashMap<>();
    saleOrderMap.put("id", "saleOrder.ID");
    saleOrderMap.put("downStreamCompanyId", "saleOrder.DOWN_STREAM_COMPANY_ID");
    saleOrderMap.put("code", "saleOrder.CODE");
    saleOrderMap.put("name", "businessEntity.NAME");
    saleOrderMap.put("extCode", "saleOrder.EXT_CODE");
    saleOrderMap.put("deliName", "saleOrder.DELI_NAME");
    saleOrderMap.put("ordState", "saleOrder.ORD_STATE");
    saleOrderMap.put("deliveryState", "saleOrder.DELIVERY_STATE");
    saleOrderMap.put("collectState", "saleOrder.COLLECT_STATE");
    saleOrderMap.put("logisticsCompanyId", "saleOrder.LOGISTICS_COMPANY_ID");
    saleOrderMap.put("createTimeStamp", "saleOrder.CREATE_TIME_STAMP");
    saleOrderMap.put("remark", "saleOrder.REMARK");
    saleOrderMap.put("inputDateTimestamp", "saleOrder.INPUT_DATE_TIMESTAMP");
    saleOrderMap.put("statementId", "saleOrder.STATEMENT_ID");
    saleOrderMap.put("businessEntityId", "saleOrder.BUSINESS_ENTITY_ID");
    saleOrderMap.put("goodsId", "item.GOODS_ID");
    saleOrderMap.put("goodsName", "item.GOODS_NAME");
    this.orderImpl.setWrapperParseMethods((propertyName -> {
      return saleOrderMap.get(propertyName);
    }));
    SQL saleOrderItemSql = new SQL() {{
      SELECT(
              SQLAliasGenerateUtil.aliasGenerate(SaleOrderItemModel.class, "item", null)
      );
      FROM("T_SALE_ORDER_ITEM item");
      INNER_JOIN("T_SALE_ORDER saleOrder ON saleOrder.ID = item.SALE_ORDER_ID");
    }};
    this.itemImpl.setQuerySql(saleOrderItemSql);
    //初始化查询条件解析 saleOrderMap
    Map<String, String> saleOrderItemMap = new HashMap<>();
    saleOrderItemMap.put("id", "item.ID");
    saleOrderItemMap.put("downStreamCompanyId", "saleOrder.DOWN_STREAM_COMPANY_ID");
    saleOrderItemMap.put("code", "saleOrder.CODE");
    saleOrderItemMap.put("ordState", "saleOrder.ORD_STATE");
    saleOrderItemMap.put("deliveryState", "saleOrder.DELIVERY_STATE");
    saleOrderItemMap.put("collectState", "saleOrder.COLLECT_STATE");
    saleOrderItemMap.put("createTimeStamp", "saleOrder.CREATE_TIME_STAMP");
    saleOrderItemMap.put("inputDateTimestamp", "saleOrder.INPUT_DATE_TIMESTAMP");
    saleOrderItemMap.put("statementId", "saleOrder.STATEMENT_ID");
    saleOrderItemMap.put("businessEntityId", "saleOrder.BUSINESS_ENTITY_ID");
    saleOrderItemMap.put("goodsId", "item.GOODS_ID");
    saleOrderItemMap.put("goodsName", "item.GOODS_NAME");
    this.itemImpl.setWrapperParseMethods((propertyName -> {
      return saleOrderItemMap.get(propertyName);
    }));
  }
}
